#include "byte_array.h"
#include "endian.h"
#include "log.h"

#include <bits/types/struct_iovec.h>
#include <cerrno>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <cmath>
#include <fstream>
#include <memory>
#include <sstream>

ByteArray::Node::Node()
:ptr(nullptr)
,next(nullptr)
,size(0)
{
}

ByteArray::Node::Node(size_t s)
:ptr(new char[s])
,next(nullptr)
,size(s)
{
}

ByteArray::Node::~Node()
{
    if(ptr)
    {
        delete[] ptr;
    }
}

//构造函数 初始化每一个节点的内存块大小
ByteArray::ByteArray(size_t base_size)
:m_baseSize(base_size),
m_position(0),
m_capacity(base_size),
m_size(0),
m_endian(BIG_ENDIAN),
m_root(new Node(base_size)), 
m_cur(m_root)     
{
}

//析构释放所有Node
ByteArray::~ByteArray()
{
    Node* tmp = m_root;
    while(tmp)
    {
        m_cur = tmp;
        tmp = tmp->next;
        delete m_cur;
    }
}


//写入固定长度int8_t类型的数据
void ByteArray::writeFint8(int8_t value)
{
    write(&value, sizeof(value));
}


//写入固定长度uint8_t类型的数据
void ByteArray::writeFuint8(uint8_t value)
{
    write(&value, sizeof(value));
}

//写入固定长度int16_t类型的数据(大端/小端)
void ByteArray::writeFint16(int16_t value)
{
    if(m_endian != BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

//写入固定长度uint16_t类型的数据(大端/小端)
void ByteArray::writeFuint16(uint16_t value)
{
    if(m_endian != BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

//写入固定长度int32_t类型的数据(大端/小端)
void ByteArray::writeFint32(int32_t value)
{
    if(m_endian != BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

//写入固定长度uint32_t类型的数据(大端/小端)
void ByteArray::writeFuint32(uint32_t value)
{
    if(m_endian != BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

//写入固定长度int64_t类型的数据(大端/小端)
void ByteArray::writeFint64(int64_t value)
{
    if(m_endian != BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

//写入固定长度uint64_t类型的数据(大端/小端)
void ByteArray::writeFuint64(uint64_t value)
{
    if(m_endian != BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}


//将有符号数转换为无符号数
static uint32_t EncodeZigzag32(const int32_t& v)
{
    if(v < 0)
    {
        return ((uint32_t)(-v)) * 2 - 1;  //确保负数编码后的无符号整数的最低有效位是1。
    }
    else
    {
        return v * 2;   //确保正数编码后的无符号整数的最低有效位是0。
    }
}
static uint64_t EncodeZigzag64(const int64_t& v)
{
    if(v < 0)
    {
        return ((uint64_t)(-v)) * 2 - 1;
    }
    else
    {
        return v * 2;
    }
}

/*
EncodeZigzag：
v = -2;
-v = 2
((uint32_t)(2)) * 2 - 1 = 4 - 1 = 3

DecodeZigzag：
v = 3（二进制：00000011）
v >> 1 = 1（二进制：00000001，相当于/2）
-(v & 1) = -1（判断最低有效位的值：最低有效位是1，表示原始数是负数）
1 ^ -1 = -2 (^:两个操作数对应二进制位相同则结果位为0，不同则为1)
*/

//将无符号数转换为有符号数
static int32_t DecodeZigzag32(const uint32_t& v)
{
    return (v >> 1) ^ -(v & 1);
}
static int64_t DecodeZigzag64(const uint64_t& v)
{
    return (v >> 1) ^ -(v & 1);
}


//写入有符号Varint32类型的数据
void ByteArray::writeInt32(int32_t value)
{
    writeUint32(EncodeZigzag32(value));
}

//写入无符号Varint32类型的数据
void ByteArray::writeUint32(uint32_t value)
{
    //变长编码（Variable-Length Encoding, VLE）可以将较小的整数使用较少的字节进行存储，同时对于较大的整数使用更多的字节
    // 每个字节的最高位用来标记是否有后续字节（最高位为1表示有更多字节，最高位为0表示这是最后一个字节）。
    // 每个字节的低7位存储实际数据。
    // 数值不断右移7位，直到数值小于128为止。

    uint8_t tmp[5]; //四个字节的数据极端情况下可能会压缩为5字节
    uint8_t i = 0;
    //去除无符号整数的二进制表示中的前导0
    while(value >= 0x80) //0x80 = 128 = 1000 0000
    {
        //1.将 value 的低7位（0x7F = 0111 1111）提取出来
        //2.将最高位设置为1，这是为了标记这个字节是否是最后一个字节。
        tmp[i++] = (value & 0x7F) | 0x80;
        value >>= 7;
    }
    tmp[i++] = value; //无需设置最高位，因为这是最后一个字节
    write(tmp, i);
}

//写入有符号Varint64类型的数据
void ByteArray::writeInt64(int64_t value)
{
    writeUint64(EncodeZigzag64(value));
}

//写入无符号Varint64类型的数据
void ByteArray::writeUint64(uint64_t value)
{
    uint8_t tmp[10];
    uint8_t i = 0;
    while(value >= 0x80) 
    {
        tmp[i++] = (value & 0x7F) | 0x80;
        value >>= 7;
    }
    tmp[i++] = value;
    write(tmp, i);
}

//写入float类型的数据
void ByteArray::writeFloat(float value)
{
    uint32_t v;
    memcpy(&v, &value, sizeof(value));
    writeFuint32(v);
}

//写入double类型的数据
void ByteArray::writeDouble(double value)
{
    uint64_t v;
    memcpy(&v, &value, sizeof(value));
    writeFuint64(v);
}

//写入std::string类型的数据,用uint16_t作为长度类型
void ByteArray::writeStringF16(const std::string& value)
{
    writeFuint16(value.size());
    write(value.c_str(), value.size());
}

//写入std::string类型的数据,用uint32_t作为长度类型
void ByteArray::writeStringF32(const std::string& value)
{
    writeFuint32(value.size());
    write(value.c_str(), value.size());
}

//写入std::string类型的数据,用uint64_t作为长度类型
void ByteArray::writeStringF64(const std::string& value)
{
    writeFuint64(value.size());
    write(value.c_str(), value.size());
}

//写入std::string类型的数据,用无符号Varint64作为长度类型
void ByteArray::writeStringVint(const std::string& value)
{
    writeUint64(value.size());
    write(value.c_str(), value.size());
}


//写入std::string类型的数据,无长度
void ByteArray::writeStringWithoutLength(const std::string& value)
{
    write(value.c_str(), value.size());
}

//读取int8_t类型的数据
int8_t ByteArray::readFint8()
{
    int8_t v;
    read(&v, sizeof(v));
    return v;
}

//读取uint8_t类型的数据
uint8_t ByteArray::readFuint8()
{
    uint8_t v;
    read(&v, sizeof(v));
    return v;
}

#define XX(type)                 \
    type v;                      \
    read(&v, sizeof(v));         \
    if(m_endian == BYTE_ORDER)   \
    {                            \
        return(v);               \
    }                            \
    return(byteswap(v)); 



//读取int16_t类型的数据
int16_t ByteArray::readFint16()
{
    XX(int16_t);
}

//读取uint16_t类型的数据
uint16_t ByteArray::readFuint16()
{
    XX(uint16_t);
}

//读取int32_t类型的数据
int32_t ByteArray::readFint32()
{
    XX(uint32_t);
}

//读取uint32_t类型的数据
uint32_t ByteArray::readFuint32()
{
    XX(uint32_t);
}

//读取int64_t类型的数据
int64_t ByteArray::readFint64()
{
    XX(int64_t);
}

//读取uint64_t类型的数据
uint64_t ByteArray::readFuint64()
{
    XX(uint64_t);
}

#undef XX


//读取有符号Varint32类型的数据
int32_t ByteArray::readInt32()
{
    return DecodeZigzag32(readUint32());
}

//读取无符号Varint32类型的数据
uint32_t ByteArray::readUint32()
{
    uint32_t result = 0;
    for(int i = 0; i < 32; i += 7)
    {
        uint8_t b = readFuint8();    //读取低8位的数据
        if(b < 0x80) //检查字节的最高位是否为0。如果是0，表示这是最后一个字节。
        {
            //1.将字节的值（直接转换为32位无符号整数）左移 i 位
            //2.与 result 进行按位或操作，将其合并到结果中 (| 相同二进制位有1就为1)
            result |= ((uint32_t)b) << i; 
            break;
        }
        else    //表示还有后续字节
        {
            //将字节的低7位左移 i 位,并与 result 进行按位或操作，将其合并到结果中
            result |= (((uint32_t)(b & 0x7f)) << i);
        }
    }
    return result;
}

//读取有符号Varint64类型的数据
int64_t ByteArray::readInt64()
{
    return DecodeZigzag64(readUint64());
}

//读取无符号Varint64类型的数据
uint64_t ByteArray::readUint64()
{
    uint64_t result = 0;
    for(int i = 0; i < 64; i += 7)
    {
        uint8_t b= readFuint8();    //读取底8位的数据
        if(b < 0x80)
        {
            // | 相同二进制位有1就为1
            result |= ((uint64_t)b) << i; 
            break;
        }
        else
        {
            //去除高位设置的1
            result |= (((uint64_t)(b & 0x7f)) << i);
        }
    }
    return result;
}


//读取float类型的数据
float ByteArray::readFloat()
{
    uint32_t v = readFuint32();
    float value;
    memcpy(&value, &v, sizeof(v));
    return value;
}

//读取double类型的数据
double ByteArray::readDouble()
{
    uint64_t v = readFuint64();
    double value;
    memcpy(&value, &v, sizeof(v));
    return value;
}

//读取std::string类型的数据,用uint16_t作为长度
std::string ByteArray::readStringF16()
{
    uint16_t len = readFuint16();
    std::string buff;
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}

//读取std::string类型的数据,用uint32_t作为长度
std::string ByteArray::readStringF32()
{
    uint32_t len = readFuint32();
    std::string buff;
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}

//读取std::string类型的数据,用uint64_t作为长度
std::string ByteArray::readStringF64()
{
    uint64_t len = readFuint64();
    std::string buff;
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}

//读取std::string类型的数据,用无符号Varint64作为长度
std::string ByteArray::readStringVint()
{
    uint64_t len = readUint64();
    std::string buff;
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}

//清空ByteArray
void ByteArray::clear()
{
    m_position = m_size = 0;
    m_capacity = m_baseSize;
    Node* tmp = m_root->next;
    while(tmp)
    {
        m_cur = tmp;
        tmp = tmp->next;
        delete m_cur;
    }
    m_cur = m_root;
    m_root->next = NULL;
}

//写入size长度的数据
void ByteArray::write(const void* buf, size_t size)
{
    if(size == 0) return;

    addCapacity(size); //扩容ByteArray

    size_t npos = m_position % m_baseSize; //计算当前节点中的 操作位置（当前节点中内存可写的位置）
    size_t ncap = m_cur->size - npos;      //当前节点内存剩余可写的数量

    size_t bpos = 0;  //当前已经写入内存的数量
    while(size > 0)
    {
        //当前内存块可以一次性分配内存
        if(ncap >= size)
        {
            memcpy(m_cur->ptr + npos, (const char*)buf + bpos, size);

            //如果当前内存块的内存刚好分配完
            if(m_cur->size == npos + size)
            {
                m_cur = m_cur->next;
            }

            m_position += size;
            bpos += size;
            size = 0;
        }
        else
        {
            //先将当期内存块的内存分配完
            memcpy(m_cur->ptr + npos, (const char*)buf + bpos, ncap);

            m_position += ncap;
            bpos += ncap;
            size -= ncap;
            m_cur = m_cur->next;    //更新内存块
            ncap = m_cur->size;     //更新内存块可用内存数量
            npos = 0;               //更新内存块可用内存起始位置
        }
    }

    if(m_position > m_size)
    {
        m_size = m_position;
    }
}

//读取size长度的数据
void ByteArray::read(void* buf, size_t size)
{
    if(size > getReadSize())
    {
        throw std::out_of_range("not enough len");  
    }

    size_t npos = m_position % m_baseSize;  //计算当前节点中的 操作位置（当前节点中内存可读的位置）
    size_t ncap = m_cur->size - npos;       //当前节点内存剩余可读数量

    size_t bpos = 0;    //当前已经读出内存的数量
    while(size > 0) 
    {
        if(ncap >= size) 
        {
            memcpy((char*)buf + bpos, m_cur->ptr + npos, size);
            if(m_cur->size == (npos + size)) 
            {
                m_cur = m_cur->next;
            }
            m_position += size;
            bpos += size;
            size = 0;
        } 
        else 
        {
            memcpy((char*)buf + bpos, m_cur->ptr + npos, ncap);
            m_position += ncap;
            bpos += ncap;
            size -= ncap;
            m_cur = m_cur->next;
            ncap = m_cur->size;
            npos = 0;
        }
    }
}

//读取size长度的数据    这个read不会影响到m_baseSize
void ByteArray::read(void* buf, size_t size, size_t position) const
{
    if(size > (m_size - position)) 
    {
        throw std::out_of_range("not enough len");
    }

    size_t npos = position % m_baseSize;
    size_t ncap = m_cur->size - npos;
    size_t bpos = 0;
    Node* cur = m_cur;

    while(size > 0) 
    {
        if(ncap >= size) 
        {
            memcpy((char*)buf + bpos, cur->ptr + npos, size);
            if(cur->size == (npos + size)) 
            {
                cur = cur->next;
            }
            position += size;
            bpos += size;
            size = 0;
        } 
        else
        {
            memcpy((char*)buf + bpos, cur->ptr + npos, ncap);
            position += ncap;
            bpos += ncap;
            size -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
    }
}

//设置ByteArray当前位置
void ByteArray::setPosition(size_t v)
{
    if(v > m_capacity) 
    {
        throw std::out_of_range("set_position out of range");
    }

    m_position = v;
    if(m_position > m_size)
    {
        m_size = m_position;
    }

    m_cur = m_root;
    while(v > m_cur->size)
    {
        v -= m_cur->size;
        m_cur = m_cur->next;
    }
    if(v == m_cur->size)
    {
        m_cur = m_cur->next;
    }
}

//把ByteArray的数据写入到文件中
bool ByteArray::writeToFile(const std::string& name) const
{
    std::ofstream ofs;
    ofs.open(name, std::ios::trunc | std::ios::binary); //二进制形式覆盖写
    if(!ofs)
    {
        log_error("writeToFile name:{} error, errno:{}, errstr:{}", name, errno, strerror(errno));
        return false;
    }

    int64_t read_size = getReadSize();
    int64_t pos = m_position;
    Node* cur = m_cur;

    while(read_size > 0)
    {
        int diff = pos % m_baseSize;
        int64_t len = (read_size > (int64_t)m_baseSize ? m_baseSize : read_size) - diff;
        ofs.write(cur->ptr + diff, len);
        cur = cur->next;
        pos += len;
        read_size -= len;
    }

    ofs.close();
    return true;
}

//从文件中读取数据
bool ByteArray::readFromFile(const std::string& name)
{
    std::ifstream ifs;
    ifs.open(name, std::ios::binary); //二进制形式覆盖写
    if(!ifs)
    {
        log_error("readFromFile name:{} error, errno:{}, errstr:{}", name, errno, strerror(errno));
        return false;
    }

    std::shared_ptr<char>buffer(new char[m_baseSize], [](char* ptr){
        delete [] ptr;
    });

    while(!ifs.eof())
    {
        ifs.read(buffer.get(), m_baseSize);
        this->write(buffer.get(), ifs.gcount());
    }

    ifs.close();
    return true;
}

//是否是小端
bool ByteArray::isLittleEndian() const
{
    return m_endian == LITTLE_ENDIAN;
}

//设置是否为小端
void ByteArray::setIsLittleEndian(bool val)
{
    if(val)
    {
        m_endian = LITTLE_ENDIAN;
    }
    else
    {
        m_endian = BIG_ENDIAN;
    }
}

//将ByteArray里面的数据[m_position, m_size)转成std::string
std::string ByteArray::toString() const
{
    std::string str;
    str.resize(getReadSize());
    if(str.empty())
    {
        return str;
    }

    read(&str[0], str.size(), m_position);
    return str;
}

//将ByteArray里面的数据[m_position, m_size)转成16进制的std::string(格式:FF FF FF)
std::string ByteArray::toHexString() const
{
    std::string str = toString();
    std::stringstream oss;

    for(size_t i = 0; i < str.size(); ++i)
    {
        if(i > 0 && i % 32 == 0)    //每行显示32个字符
        {
            oss << std::endl;
        }

        //std::setw 设置输出宽度（8位二进制数可以表示2位16进制数）
        //std::setfill 设置填充字符，默认为空格
        // str[i] 是一个 char 类型（有符号8位）。
        // (uint8_t)str[i] 将其转换为无符号8位整数，以确保其值在0到255之间。
        // (int)(uint8_t)str[i] 将其进一步转换为整数类型，以便正确进行16进制显示。
        oss << std::setw(2) << std::setfill('0') << std::hex 
            << (int)(uint8_t)str[i] << " ";
    }

    return oss.str();
}

//获取可读取的缓存,保存成iovec数组
// struct iovec {
//     void  *iov_base; // 数据块的地址
//     size_t iov_len;  // 数据块的大小
// };
uint64_t ByteArray::getReadBuffers(std::vector<iovec>& buffers, uint64_t len) const
{
    len = len > getReadSize() ? getReadSize() : len;
    if(len == 0)
    {
        return 0;
    }

    uint64_t size = len;
    size_t npos = m_position % m_baseSize;
    size_t ncap = m_cur->size - npos;
    struct iovec iov;
    Node* cur = m_cur;

    while(len > 0)
    {
        if(ncap >= len) //如果可以一次性读出数据
        {
            iov.iov_base = cur->ptr + ncap;
            iov.iov_len = len;
            len = 0;
        }
        else 
        {
            iov.iov_base = cur->ptr + ncap;
            iov.iov_len = ncap;

            len -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
        buffers.emplace_back(iov);
    }
    return size;
}

//获取可读取的缓存,保存成iovec数组,从position位置开始
uint64_t ByteArray::getReadBuffers(std::vector<iovec>& buffers, uint64_t len, uint64_t position) const
{
    len = len > getReadSize() ? getReadSize() : len;
    if(len == 0)
    {
        return 0;
    }

    uint64_t size = len;
    size_t npos = position % m_baseSize;  //可用内存在当前节点中的起始位置

    Node* cur = m_root;
    size_t count = position / m_baseSize;
    while(count > 0)
    {
        cur = cur->next;
        --count;
    }

    size_t ncap = m_cur->size - npos;     //当前节点内存剩余可用数量
    struct iovec iov;

    while(len > 0)
    {
        if(ncap >= len)
        {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = len;
            len = 0;
        }
        else
        {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = ncap;
            len -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
        buffers.push_back(iov);
    }
    return size;
}

//获取可写入的缓存,保存成iovec数组
uint64_t ByteArray::getWriteBuffers(std::vector<iovec>& buffers, uint64_t len)
{
    if(len == 0)
    {
        return 0;
    }
    addCapacity(len);

    uint64_t size = len;
    size_t npos = m_position % m_baseSize;
    size_t ncap = m_cur->size - npos;
    struct iovec iov;
    Node* cur = m_cur;

    while(len > 0) {
        if(ncap >= len) //如果当前节点可以存得下所有数据
        {
            iov.iov_base = cur->ptr + npos; 
            iov.iov_len = len;
            len = 0;
        } 
        else 
        {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = ncap;

            len -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
        buffers.push_back(iov);
    }
    return size;
}


//扩容ByteArray,使其可以容纳size个数据(如果原本可以可以容纳,则不扩容)
void ByteArray::addCapacity(size_t size)
{
    if(size == 0) return;

    size_t old_cap = getCapacity();

    //如果当前块的内存够用
    if(old_cap >= size)
    {
        return;
    }

    //计算需要开辟多少个块
    size = size - old_cap;
    size_t count = ceil(1.0 * size / m_baseSize); //ceil向上取整
    Node* tmp = m_root;
    while(tmp->next)
    {
        tmp = tmp->next;
    }

    Node* first = NULL; //用于保存第一个新块
    for(size_t i = 0; i < count; ++i)
    {
        tmp->next = new Node(m_baseSize);
        if(first == NULL)
        {
            first = tmp->next;
        }
        tmp = tmp->next;
        m_capacity += m_baseSize;
    }

    if(old_cap == 0)
    {
        m_cur = first;
    }
}